package br.ufrj.dcc.versionspaces.impl;

import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import jpl.Atom;
import jpl.Query;
import jpl.Term;
import jpl.Variable;
import br.ufrj.dcc.versionspaces.AbstractVersionSpaces;

/**
 * Interface class for prolog versionspaces algorithm.
 * @author Pedro Rougemont
 *
 */
public class PrologVersionSpacesImpl implements AbstractVersionSpaces {

	/** Holds the current state of the execution. */
	private int state;
	/** Holds the size of training set. */
	private int numberOfExamples;
	/** Holds the assert query. */
	private String assertions = "";
	/** Holds the attribute names. */
	private List<String> attributes;
	/** Matrix where columns match attributes and rows examples. */
	private String[][] examplesTable;
	/** Holds the goal attribute. */
	private String goalAttribute;
	
	public PrologVersionSpacesImpl() {
		numberOfExamples = 0;
	}
	
	public void declareAttributeDomain(String attribute, List<String> attributeDomain) {
		
		assertions += "dom(" + attribute + ",[";
		for (Iterator<String> iterator = attributeDomain.iterator(); iterator.hasNext();) {
			assertions += iterator.next();
			if(iterator.hasNext()) assertions += ",";
		}
		assertions += "]).\n";
		
	}
	
	public void declareAttributes(List<String> attributes) {		
		
		assertions += "atrib([";
		for (Iterator<String> iterator = attributes.iterator(); iterator.hasNext();) {
			assertions += iterator.next();
			if(iterator.hasNext()) assertions += ",";
		}
		assertions += "]).\n";
		
		this.attributes = attributes;		
	}
	
	
	public void declareExamples(String attribute, List<String> attributeColumn) {
		
		for(int j = 0; j < attributes.size(); j++) {
			if(examplesTable[0][j + 1].equals(attribute)) {
				for(int i = 0; i < numberOfExamples; i++) {
					examplesTable[i + 1][j + 1] = attributeColumn.get(i);
				}
			}
		}
	}

	public void declareGoalAttribute(String attribute) {
		goalAttribute = attribute;
		assertions += "atrib_alv(" + attribute + ").\n";		
	}

	public void declareGoalAttributeDomain(List<String> attributeDomain) {
		
		assertions += "dom_alv([";
		for (Iterator<String> iterator = attributeDomain.iterator(); iterator.hasNext();) {
			assertions += iterator.next();
			if(iterator.hasNext()) assertions+= ",";
		}	
		assertions += "]).\n";
		
	}

	public void declareGoals(List<String> attributeColumn) {
		
		for (int i = 0; i < numberOfExamples; i++) {
			examplesTable[i + 1][attributes.size() + 1] = attributeColumn.get(i);
		}
		
		String buffer = "";
		for (int i = 1; i < examplesTable.length; i++) {
			buffer = "";
			for (int j = 1; j < examplesTable[i].length - 1; j++) {
				buffer += examplesTable[i][j];
				if(j+1 != examplesTable[i].length - 1) buffer += ",";
			}
			assertions += "ex(" + examplesTable[i][0] + ",[" + buffer + "]," +
						   examplesTable[i][attributes.size() + 1] + ").\n";

		}
	}

	public void setNumberOfTrainingEntries(int numberOfExamples) {
		this.numberOfExamples = numberOfExamples;
		
		int attributesSize = attributes.size();
				
		examplesTable = new String[numberOfExamples + 1][attributesSize + 2];
		
		examplesTable[0][0] = "examples\\attributes";
		
		int j;
		for ( j = 0; j < attributesSize; j++) {
			examplesTable[0][j + 1] = attributes.get(j);
		}	
		examplesTable[0][j + 1] = goalAttribute;
		
		assertions += "linhas([";
		for (int i = 0; i < numberOfExamples; i++) {
			examplesTable[i + 1][0] = "ex" + i;
			assertions += "ex" + i;
			if(i + 1 < numberOfExamples) assertions += ",";
		}
		assertions += "]).\n";		
	}

	public List<String[]>[] buildVersionSpace() {
		
		PrintWriter out1 = null;
		DataInputStream in1 = null;
		File versionspaces = new File("versionspace.pl");
		String buffer = "";
		String text = "";
		List<String[]>[] SeG = new Vector[2];
		
		try {
			out1 = new PrintWriter(new BufferedWriter(new FileWriter(versionspaces)));
			in1 = new DataInputStream(new FileInputStream((new File("")).getAbsolutePath()
														  + "\\src\\main\\prolog"
														  + "\\br\\ufrj\\dcc\\versionspaces\\" 
														  + "versionspaces.pl"));
			
			while((buffer = in1.readLine()) != null){			
				text += buffer + "\n ";
			}
			
			out1.write(assertions + "\n" + text);
			
			out1.close();
			in1.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		Query init = new Query("consult", new Term[] {new Atom("versionspace.pl")});
		System.out.println(init.hasSolution()? "Prolog Started" : "Prolog Failed");		
		
		List<String[]> retorno = new ArrayList<String[]>();
		Variable L = new Variable("L");
		Variable S = new Variable("S");
		Variable G = new Variable("G");
		Query consult =  new Query("eliminacao", new Term[]{L,S,G});
		Hashtable[] ht = consult.allSolutions();
		
		Object result = ht[0].get("S");
		String parsableS = result.toString();
				
		parsableS = parsableS.replaceAll("(\\,\\ \\[)","");
		parsableS = parsableS.replaceAll("['.']","");
		parsableS = parsableS.replaceAll("[(\\)\\[\\]]","");
		String[] SArray = parsableS.split("[,]");

		for (int i = 0; i < SArray.length; i++) {
			SArray[i] = SArray[i].trim();			
		}
		List<String[]> vectorS = new Vector<String[]>();
		vectorS.add(SArray);
		SeG[1] = vectorS;
				
		result = ht[0].get("G");
		String parsableG = result.toString();
		
		parsableG = parsableG.replaceAll("['.']","");
		parsableG = parsableG.replaceAll("[(\\)\\[\\]]","");
		String[] GArray = parsableG.split("(,\\ ,\\ )");
		List<String[]> vectorG = new Vector<String[]>();
		for (int i = 0; i < GArray.length; i++) {
			System.out.println(GArray[i]);
		}
		for (int i = 0; i < GArray.length; i++) {
			GArray[i] = GArray[i].trim();
			String[] hypothesis  = GArray[i].split("[,]");
			for (int j = 0; j < hypothesis.length; j++) {
				hypothesis[j] = hypothesis[j].trim();
			}
			vectorG.add(hypothesis);
		}
		SeG[0] = vectorG;
		
		return SeG;
	}
	
	public static void main(String[] args) {
		PrologVersionSpacesImpl prologVersionSpacesImpl = new PrologVersionSpacesImpl();
		
		prologVersionSpacesImpl.buildVersionSpace();
	}
}
